#include <iostream>
#include <fstream>
#include <string>

#include "errors.h"
#include "tokenizer.h"
#include "basicparser.h"
#include "basicparser2.h"
#include "parser.h"
#include "cmd.h"

using namespace std;

/* 
	If current profile is Debug then the following array will be passed as options
*/

#ifdef _DEBUG

// "--tokenizer-only"
// "--expressions-parser-only"
// "--expressions-parser2-only"
// "--parser-only"
// "--ParserWithSymTable-only"
char *options[] = 
{
	"--ParserWithSymTable-only",
	//"C:\\Users\\Kravitz\\Documents\\Visual Studio 2008\\Projects\\ccompiler\\tests\\tests\\ParserWithSymTable\\08.tst",
    "tests\\tests\\ParserWithSymTable\\04.tst" 
	//"D:\\work\\ccompiler\\tests\\tests\\ParserWithSymTable\\04.tst"
};
#endif

int main(int argc, char *argv[])
{
	string filename;
	char **args = argv;
#ifdef _DEBUG
	{
        argc = (sizeof(options) / sizeof(char *) + 1);     
		args = new char *[argc];
		args[0] = argv[0];
		for(int i = 1; i < argc; ++i)
		{
			args[i] = options[i-1];
		}
	}
#endif
	try
	{
        cmd::parseCmd(argc, args);
	}
	catch(CCompiler::Errors::CmdOptionsError)
	{
		cout << "Wrong command string" << endl;
	}
	if(cmd::needToPrintHelp())
	{
		cout << "CCompiler by Kravtsov Dmitriy" << endl;
		cout << "Implemented components:" << "tokenizer, expressions parser" << endl;
		cout << "To use type: ccompiler.exe [options] <filename>" << endl;
		cout << "Available options are:" << endl;
		cout << "\t--tokenizer-only - use only tokenizer" << endl;
		cout << "\t--expressions-parser-only - use only expressions parser" << endl;
	}
    else
    {
		filename = cmd::getFilename();
        try
        {
			ifstream file(filename.c_str());
            CCompiler::Tokenizer tokenizer(file);
			if(cmd::lexerOptionEnabled())
			{
				CCompiler::Token t = tokenizer.getCurToken();
				do
				{
					if(t.getTokenType() == CCompiler::ttEof) break;
					cout << t;
					if(t.getTokenType() == CCompiler::ttError) break;
					t = tokenizer.nextToken();
				} while(true);
			}
			else if(cmd::parseExpressionsOptionEnabled())
			{
				CCompiler::BasicParser parser(tokenizer);
				while(tokenizer.getCurToken().getTokenType() != CCompiler::ttEof)
				{
					CCompiler::SynNode *expr = parser.parseExpression();
					expr->print(std::cout);
					delete expr;
				}
			}
			else if(cmd::parseExpressions2OptionEnabled())
			{
				CCompiler::BasicParser2 parser(tokenizer);
				while(tokenizer.getCurToken().getTokenType() != CCompiler::ttEof)
				{
					CCompiler::SynNode *expr = parser.parseExpression2();
					expr->print(std::cout);
					delete expr;
				}
			}
			else if(cmd::parserWithSymTableOptionEnabled())
			{
				CCompiler::ParserWithSymTable parser(tokenizer);
				try
				{
					while(tokenizer.getCurToken().getTokenType() != CCompiler::ttEof)
					{
						CCompiler::SynNode *expr = parser.parse();
						expr->print(std::cout);
						delete expr;
					}
				}
				catch(.../*CCompiler::Errors::EndOfFile*/) 
				{
                    parser.print(cout << "::Global table\n");
                    cout << "::End of global table\n";
                    throw;
				}
				parser.print(cout << "::Global table\n");
			    cout << "::End of global table\n";
            }
        }
        catch(CCompiler::Errors::BrokenStream)
        {
            cout << "Unable to read from file " << filename;
        }
		catch(CCompiler::Errors::SyntaxError e)
		{
			cout << e;
		}
		catch(CCompiler::Errors::TokenError e)
		{
			cout << e;
		}
		catch(CCompiler::Errors::EndOfFile)
		{}
	}
#ifdef _DEBUG
	delete[] args;
#endif
}
